////////////////////////////////////////////////////////////////////////////////

#include "client_gui.h"

////////////////////////////////////////////////////////////////////////////////

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>

////////////////////////////////////////////////////////////////////////////////


ClientGUI::ClientGUI()
:m_Screen(NULL), m_Player(NULL),
m_Network(m_RecvQueue,
          m_SendQueue,
          m_SendQueueMutex,
          m_RecvQueueMutex,
          "localhost",
          "37015",
          "37016")
{
    // Init SDL
    SDL_Init( SDL_INIT_EVERYTHING );

    const int width = 640;
    const int height = 480;
    const int bitsPerPixel = 32;

    //Set up the screen
    m_Screen = SDL_SetVideoMode( width, height, bitsPerPixel, SDL_HWSURFACE );

    //Set the window caption
    SDL_WM_SetCaption( "Shoot the music", NULL );

    // Load player image
    m_Player = LoadImage("player.png");
}


////////////////////////////////////////////////////////////////////////////////


ClientGUI::~ClientGUI()
{
    SDL_Quit();
}


////////////////////////////////////////////////////////////////////////////////


void ClientGUI::Start()
{
    // SDL event
    SDL_Event event;

    while(true)
    {
        // Start fps timer
        m_FPS.Start();

        // Process user input
        while( SDL_PollEvent(&event) )
        {
            if (event.type == SDL_QUIT)
                return;
            ProcessEvent(event);
        }

        // Save events to queue
        SaveEvents();

		Draw();

        Timer::Delay(1);

        //Cap the frame rate
        //Wait();
    }
}


////////////////////////////////////////////////////////////////////////////////


void ClientGUI::ProcessEvent( const SDL_Event& _event )
{
    // ClientEngine event
    ClientEngine::Event engineEvent = ClientEngine::INVALID;

    // Convert from SDL to internal engine event
    switch (_event.type)
    {
    case SDL_KEYDOWN:
        {
            switch (_event.key.keysym.sym)
            {
            case SDLK_w:
                engineEvent = ClientEngine::W_DOWN;
                break;
            case SDLK_s:
                engineEvent = ClientEngine::S_DOWN;
                break;
            case SDLK_a:
                engineEvent = ClientEngine::A_DOWN;
                break;
            case SDLK_d:
                engineEvent = ClientEngine::D_DOWN;
                break;
            default:
                break;
            }

            break;
        }

    ////////////////////////////////////////

    case SDL_KEYUP:
        {
            switch (_event.key.keysym.sym)
            {
            case SDLK_w:
                engineEvent = ClientEngine::W_UP;
                break;
            case SDLK_s:
                engineEvent = ClientEngine::S_UP;
                break;
            case SDLK_a:
                engineEvent = ClientEngine::A_UP;
                break;
            case SDLK_d:
                engineEvent = ClientEngine::D_UP;
                break;
            default:
                break;
            }

            break;
        }

    ////////////////////////////////////////

    case SDL_MOUSEBUTTONDOWN:
        {
            switch (_event.button.button)
            {
            case SDL_BUTTON_LEFT:
                engineEvent = ClientEngine::MOUSE1_DOWN;
                break;
            default:
                break;
            }
            break;
        }

    ////////////////////////////////////////

    case SDL_MOUSEBUTTONUP:
        {
            switch (_event.button.button)
            {
            case SDL_BUTTON_LEFT:
                engineEvent = ClientEngine::MOUSE1_UP;
                break;
            default:
                break;
            }
            break;
        }

    ////////////////////////////////////////

    case SDL_MOUSEMOTION:
        m_Engine.ProcessMouseMotion(_event.motion.x, _event.motion.y);
        break;

    default:
        return;
    }

    m_Engine.ProcessEvent(engineEvent);
}


////////////////////////////////////////////////////////////////////////////////


void ClientGUI::Draw()
{
    m_RecvQueueMutex.Lock();

    while ( !m_RecvQueue.empty() )
    {
        // Fill the screen white
        SDL_FillRect( m_Screen,
                      &m_Screen->clip_rect,
                      SDL_MapRGB( m_Screen->format, 0xFF, 0xFF, 0xFF ) );

        ServerPacket& packet = m_RecvQueue.back();

        // Draw players
        for (size_t i = 0; i < packet.m_Players.size(); ++i)
        {
            int x = packet.m_Players[i].first;
            int y = packet.m_Players[i].second;

            ApplySurface(x, y, m_Player, m_Screen);
        }

        // Draw bullets
        for (size_t i = 0; i < packet.m_Bullets.size(); ++i)
        {
            int x = packet.m_Bullets[i].first;
            int y = packet.m_Bullets[i].second;

            //ApplySurface(x, y, m_Bullet, m_Screen);
        }
        
        // Update the screen
        SDL_Flip( m_Screen );

        m_RecvQueue.pop();
    }

    m_RecvQueueMutex.Unlock();
}


////////////////////////////////////////////////////////////////////////////////


SDL_Surface* ClientGUI::LoadImage( std::string _fileName )
{
    //The image that's loaded
    SDL_Surface* loadedImage = NULL;

    //The optimized surface that will be used
    SDL_Surface* optimizedImage = NULL;

    //Load the image
    loadedImage = IMG_Load( _fileName.c_str() );

    //If the image loaded
    if( loadedImage != NULL )
    {
        //Create an optimized surface
        optimizedImage = SDL_DisplayFormat( loadedImage );

        //Free the old surface
        SDL_FreeSurface( loadedImage );

        //If the surface was optimized
        if( optimizedImage != NULL )
        {
            //Color key surface
            SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB( optimizedImage->format, 0xFF, 0xFF, 0xFF ) );
        }
    }

    //Return the optimized surface
    return optimizedImage;
}


////////////////////////////////////////////////////////////////////////////////


void ClientGUI::ApplySurface( int x,
                        int y,
                        SDL_Surface* source,
                        SDL_Surface* destination,
                        SDL_Rect* clip /* = NULL */ )
{
    //Holds offsets
    SDL_Rect offset;

    //Get offsets
    offset.x = x;
    offset.y = y;

    //Blit
    SDL_BlitSurface( source, clip, destination, &offset );
}


////////////////////////////////////////////////////////////////////////////////


void ClientGUI::SaveEvents()
{
    
    static ClientPacket prevPacket;

    ClientPacket packet;
    packet.m_KeyFlags = m_Engine.GetKeyFlags();
    packet.m_MousePosition = m_Engine.GetMousePosition();

    // Do not send same packet twice
    if (packet != prevPacket)
    {
        prevPacket = packet;

        m_SendQueueMutex.Lock();
        m_SendQueue.push(packet);
        m_SendQueueMutex.Unlock();
    }
}


////////////////////////////////////////////////////////////////////////////////
